package com.github.cosycode.imgtool.util;

import com.github.cosycode.common.ext.hub.Throws;
import com.github.cosycode.common.util.reflex.ReflexUtils;
import com.github.cosycode.imgtool.tool.RegexUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;
import java.util.regex.Pattern;

/**
 * <b>Description : </b> 文件路径类
 * <p>
 * <b>created in </b> 2022/1/6
 * </p>
 *
 * @author CPF
 * @since 1.0
 **/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PathUtils {

    public static final Pattern URL_PATTERN = Pattern.compile(RegexUtils.URL_REGEX);

    public static final Pattern WIN_DISK_PATH_REGEX = Pattern.compile(RegexUtils.WIN_DISK_PATH_REGEX);

    public static final String FILE_SPLIT_PATTERN = "/";

    /**
     * 获取该 File 文件对应的 CanonicalPath 的 File
     *
     * <p>
     * <br> 如 new File("D:/Users\.//CPF\Desktop\out\fear/../realtime")
     * <br> 转换为
     * <br> new File("D:\Users\CPF\Desktop\out\realtime")
     * </p>
     *
     * @param file 文件对象
     * @return file 对象对应的 CanonicalPath 的 File 对象
     */
    public static File getCanonicalPathFile(File file) {
        String value = Throws.sup(file::getCanonicalPath).logThrowable("getCanonicalPath 2 发生错误").value();
        if (!value.equals(file.getAbsolutePath())) {
            file = new File(value);
        }
        return file;
    }

    /**
     * 判断文件路径类型
     *
     * @param path 文件路径
     * @return 文件里路径类型
     */
    public static PathType getPathType(@NonNull String path) {
        path = path.trim();
        // 是否是 URL 路径
        if (URL_PATTERN.matcher(path).matches()) {
            return PathType.WEB_URL;
        }
        if (SystemUtils.IS_OS_WINDOWS) {
            // 是否是根目录
            if (path.startsWith("/") || path.startsWith("\\")) {
                return PathType.ROOT_PATH;
            }
            // 是否是磁盘绝对路径
            if (WIN_DISK_PATH_REGEX.matcher(path).matches()) {
                return PathType.ABSOLUTE_PATH;
            }
            // 其它全部是则 返回相对路径
            return PathType.RELATION_PATH;
        }

        // MAC and linux are preferential recognized as the root path.
        if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_LINUX) {
            if (path.startsWith("/") || path.startsWith("\\")) {
                return PathType.ROOT_PATH;
            }
            return PathType.RELATION_PATH;
        }
        throw new IllegalStateException("不支持的系统");
    }

    /**
     * 将 path 路径进行标准化转换
     *
     * <p>
     * <br> 如 D:/Users\.//CPF\Desktop\out\fear/../realtime/24144-266.png
     * <br> 转换为
     * <br> D:\Users\CPF\Desktop\out\realtime\24144-266.png
     * </p>
     *
     * @param path 路径
     * @return 标准的路径
     */
    public static String getCanonicalPath(String path) throws IOException {
        return new File(path).getCanonicalPath();
    }

    /**
     * 将 path 路径进行标准化转换
     *
     * <p>
     * <br> 如
     * <br> preFixPath: D:/Users\.//CPF\Desktop\out\fear/
     * <br> postFixPath: ../realtime/24144-266.png
     * <br> 转换为
     * <br> D:\Users\CPF\Desktop\out\realtime\24144-266.png
     * </p>
     *
     * @param preFixPath  文件路径前缀
     * @param postFixPath 文件路径后缀
     * @return 标准的路径
     */
    public static String getCanonicalPath(String preFixPath, String postFixPath) throws IOException {
        final String combinePath;
        if (preFixPath.endsWith("/") || preFixPath.endsWith("\\")) {
            combinePath = preFixPath + postFixPath;
        } else {
            combinePath = preFixPath + PathUtils.FILE_SPLIT_PATTERN + postFixPath;
        }
        return getCanonicalPath(combinePath);
    }

    /**
     * 合并多个路径片段
     *
     * @param preFixPath  文件路径前缀
     * @param postFixPath 文件路径后缀
     * @return 标准的路径
     */
    public static String concatPathClips(@NonNull String preFixPath, @NonNull String... postFixPath) {
        StringBuilder sb = new StringBuilder(preFixPath);
        for (String s : postFixPath) {
            sb.append(File.separator).append(s);
        }
        return StringUtils.strip(sb.toString(), " ").replace('\\', '/').replaceAll("[/]{2,}", "/");
    }

    /**
     * @param rootDir 项目根路径
     * @param file    文件对象
     * @param path    路径:{根路径, 相对路径, 绝对路径}
     * @return 绝对路径
     */
    public static String computePath(String rootDir, File file, String path) {
        if (path.startsWith("/")) {
            return rootDir + path;
        } else if (path.startsWith("http")) {
            return rootDir + "/" + path;
        } else if (path.startsWith(".")) {
            return file.getParentFile() + PathUtils.FILE_SPLIT_PATTERN + path;
        } else {
            return path;
        }
    }

    /**
     * 提取纯文件名
     * <p>
     * 传入 prefix/p1/p2/filename.exc, 返回 filename
     * </p>
     *
     * @param filePath 文件路径
     */
    public static String getFileName(String filePath) {
        int maxIdx = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
        return filePath.substring(maxIdx + 1);
    }

    /**
     * 提取纯文件名
     * <p>
     * 传入 prefix/p1/p2/filename.exc, 返回 filename
     * </p>
     *
     * @param filePath 文件路径
     */
    public static String getFileNamePrefix(String filePath) {
        int maxIdx = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
        int pointIdx = filePath.lastIndexOf(".");
        if (pointIdx < 0 || pointIdx < maxIdx) {
            pointIdx = filePath.length();
        }
        return filePath.substring(maxIdx + 1, pointIdx);
    }

    /**
     * 提取文件后缀名
     * <p>
     * 传入 prefix/p1/p2/filename.exc, 返回 exc
     * </p>
     *
     * @param filePath 文件名
     */
    public static String getFileNameSuffix(String filePath) {
        int maxIdx = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
        int pointIdx = filePath.lastIndexOf(".");
        if (pointIdx < 0 || pointIdx < maxIdx) {
            pointIdx = filePath.length();
        }
        return filePath.substring(pointIdx + 1);
    }

    @SuppressWarnings({"java:S4276", "java:S1075", "java:S106"})
    public static void main(String[] args) throws IOException {
        System.out.println();

        final Function<String, String> fileMethod = getFileMethod();
        String pathname = "/Users\\.//CPF\\Desktop\\out\\fere/../realtime/main-screen-shot-20210413-124144-266.png";
        System.out.println(getCanonicalPath(pathname));
        System.out.println(fileMethod.apply(pathname));
        System.out.println(getFileNamePrefix(pathname));
        System.out.println(getFileNameSuffix(pathname));
        System.out.println();
    }

    /**
     * 获取一个 规范化路径的 方法(通过反射, 从 File 里面取出来的)
     */
    @SuppressWarnings({"java:S3011", "java:S112"})
    private static Function<String, String> getFileMethod() {
        final Object fs;
        try {
            fs = ReflexUtils.getAttributeFromObject(new File(""), "fs");
            final Method canonicalize = fs.getClass().getDeclaredMethod("canonicalize", String.class);
            canonicalize.setAccessible(true);
            return s -> {
                try {
                    return (String) canonicalize.invoke(fs, s);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                    return "";
                }
            };
        } catch (NoSuchFieldException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判断路径是否是以文件夹分隔符结尾
     *
     * @param path 待验证的路径
     * @return true, 路径以 '/' or '\' 结尾
     */
    public static boolean isEndWithFileSeparator(String path) {
        return path.endsWith("/") || path.endsWith("\\");
    }


    public boolean isUrlPath(String path) {
        return URL_PATTERN.matcher(path).matches();
    }

    public boolean isRootPath(String path) {
        return path.startsWith("/") || path.startsWith("\\");
    }

    /**
     * <b>Description : </b> 文件路径类型
     * <p>
     * <b>created in </b> 2022/1/6
     * </p>
     *
     * @author CPF
     * @since 1.0
     **/
    public enum PathType {
        WEB_URL, ROOT_PATH, RELATION_PATH, ABSOLUTE_PATH
    }

}
